/** Called automatically by JsDoc Toolkit. */
function publish(symbolSet) {

    publish.conf = {  // trailing slash expected for dirs
        pagePrefix: "Class",
    	ext: ".txt",
    	outDir: JSDOC.opt.d || SYS.pwd + "../out/googlecode/",
    	templatesDir: JSDOC.opt.t || SYS.pwd + "../templates/googlecode/"
    };

    // used to allow Link to check the details of things being linked to
    Link.symbolSet = symbolSet;

    Link.symbolNameToLinkName = function(symbol) {
        return Link.hashPrefix + methodSignature(symbol);
    }

    // generate wiki links instead of <a href> tags
    Link.prototype._makeSymbolLink = function(alias) {
        var linkTo = Link.getSymbol(alias);
        if (!linkTo) {
            // if there is no symbol by that name just return the name unaltered
            return this.text || alias;
        }

        var linkPath;
        if (!linkTo.is("CONSTRUCTOR") && !linkTo.isNamespace) { // it's a method or property
            linkPath = (Link.filemap) ? Link.filemap[linkTo.memberOf] :
                       escape(linkTo.memberOf) || "Global";
            linkPath += "#" + Link.symbolNameToLinkName(linkTo);
        } else {
            linkPath = (Link.filemap) ? Link.filemap[linkTo.alias] : escape(linkTo.alias);
        }
        linkPath = linkPath.replace(".", "");

        var linkText = this.text || alias;
        var linkInner = (this.innerName ? "#" + this.innerName : "");
        var link = publish.conf.pagePrefix + anchor(linkPath + linkInner);
        return "[" + link + " " + linkText + "]";
    };
    
    // create the required templates
    try {
        var indexTemplate = new JSDOC.JsPlate(publish.conf.templatesDir + "index.tmpl");
        var classTemplate = new JSDOC.JsPlate(publish.conf.templatesDir + "class.tmpl");
    } catch(exception) {
        print("Couldn't create the required templates: " + exception);
        quit();
    }

    // get an array version of the symbolset, useful for filtering
    var symbols = symbolSet.toArray();

    // get a list of all the classes in the symbolset
    var classes = symbols.filter(function($) { return ($.is("CONSTRUCTOR") || $.isNamespace); }).sort(makeSortby("alias"));

    // create each of the class pages
    for (var i = 0, l = classes.length; i < l; i++) {
        var symbol = classes[i];
        var alias = (symbol.alias == "_global_" ? "Global" : symbol.alias).replace(".", "");

        symbol.events = symbol.getEvents();   // 1 order matters
        symbol.methods = symbol.getMethods(); // 2

        Link.currentSymbol = symbol;

        var output = classTemplate.process(symbol);
        IO.saveFile(publish.conf.outDir, publish.conf.pagePrefix + alias + publish.conf.ext, output);
    }

    var index = indexTemplate.process(classes);
    IO.saveFile(publish.conf.outDir, publish.conf.pagePrefix + "Index" + publish.conf.ext, index);
}

/** Converts the HTML tags in a text block to Google Code Wiki formatting. */
function html2wiki(text) {

    if (!text) {
        return "";
    }

    text = text.replace(/\n/g, " ");
    text = text.replace(/<h2>/g, "== ");
    text = text.replace(/<\/h2>/g, " ==");
    text = text.replace(/<p>/g, "\n\n");
    text = text.replace(/<\/p>/g, "");
    text = text.replace(/<dl>/g, "");
    text = text.replace(/<\/dl>/g, "");
    text = text.replace(/<dt>/g, "\n * ");
    text = text.replace(/<\/dt>/g, "<br>");
    text = text.replace(/<dd>/g, "");
    text = text.replace(/<\/dd>/g, "");
    text = text.replace(/<ul>/g, "\n");
    text = text.replace(/<\/ul>/g, "");
    text = text.replace(/<li>/g, "\n * ");
    text = text.replace(/<\/li>/g, "");
    text = text.replace(/<strong>/g, "*");
    text = text.replace(/<\/strong>/g, "*");
    return text;
}

/** Strips all HTML tags from a text block. */
function stripHtml(text) {

    if (!text) {
        return "";
    }

    text = text.replace(/\n/g, " ");
    text = text.replace(/<h2>/g, "");
    text = text.replace(/<\/h2>/g, "");
    text = text.replace(/<p>/g, "\n\n");
    text = text.replace(/<\/p>/g, "");
    text = text.replace(/<dl>/g, "");
    text = text.replace(/<\/dl>/g, "");
    text = text.replace(/<dt>/g, "");
    text = text.replace(/<\/dt>/g, "");
    text = text.replace(/<dd>/g, "");
    text = text.replace(/<\/dd>/g, "");
    text = text.replace(/<ul>/g, "");
    text = text.replace(/<\/ul>/g, "");
    text = text.replace(/<li>/g, "");
    text = text.replace(/<\/li>/g, "");
    text = text.replace(/<strong>/g, "");
    text = text.replace(/<\/strong>/g, "");
    return text;
}

/** Escapes a code example. */
function escapeExample(text) {

    return text;
}

/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
function summarize(desc) {

    if (typeof desc != "undefined") {
        return desc.match(/([\w\W]+?\.)[^a-z0-9_$]/i)? RegExp.$1 : desc;
    }
}

/** Make a symbol sorter by some attribute. */
function makeSortby(attribute) {

	return function(a, b) {
        if (a[attribute] != undefined && b[attribute] != undefined) {
            a = a[attribute].toLowerCase();
            b = b[attribute].toLowerCase();
            if (a < b) {
                return -1;
            } else if (a > b) {
                return 1;
            }
            return 0;
        }
    }
}

/** Pull in the contents of an external file at the given path. */
function include(path) {

	var path = publish.conf.templatesDir + path;
	return IO.readFile(path);
}

/** Build output for displaying function signature (name and parameters). */
function methodSignature(symbol) {

    var signature = symbol.name;
    if (signature) {
        signature = signature.substr(signature.indexOf(".") + 1);
        signature = signature.substr(signature.indexOf("#") + 1);
    } else {
        return "";
    }

    if (!symbol.params) {
        signature += "()";
    } else {
        signature += "(" +
            symbol.params.filter(function(param) {
                return param.name.indexOf(".") == -1; // don't show config params in signature
            }).map(function(param) {
                return param.name;
            }).join(", ") +
        ")";
    }
    return signature;
}

function anchor(string) {

    return string ? string.replace(/ /g, "_") : "";
}

/** Find symbol {@link ...} strings and function() references in text and turn into html links */
function resolveLinks(str, className) {

    if (!str) {
        return "";
    } else if (typeof str != "string") {
        str = str.toString();
    }

    str = str.replace(/([a-zA-Z0-9.:_]+\(\))/gi,
        function(match, symbolName) {
            var originalSymbolName = symbolName;
            if (symbolName.indexOf(".") == -1) {
                symbolName = className + "." + symbolName
            }
            var string = new Link().toSymbol(symbolName).toString();
            if (string[0] != "[") { // symbol wasn't found
                string = originalSymbolName;
            } else if (symbolName != originalSymbolName) {
                var splits = string.split(" ", 2);
                if (splits.length > 1) {
                    splits[1] = splits[1].replace(symbolName.substr(0, symbolName.length - 2),
                                                  originalSymbolName.substr(0, originalSymbolName.length - 2));
                }
                string = splits.join(" ");
            }
            return string;
        }
    );
    str = str.replace(/\{@link ([^} ]+) ?\}/gi,
    	function(match, symbolName) {
            return new Link().toSymbol(symbolName).toString();
    	}
    );

    return str;
}
